/*
 * terminals.c
 *
 *  Created on: 17/feb/2011
 *      Author: ivano
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "terminals.h"

terminal_t* terminal_new(void) {
	terminal_t* term = (terminal_t*) malloc(sizeof(terminal_t));
	if (term == NULL)
		return NULL;
	if (pipe(term->pipes.from_daemon) < 0)
		return NULL;
	if (pipe(term->pipes.to_daemon) < 0) {
		close(term->pipes.from_daemon[0]);
		close(term->pipes.from_daemon[1]);
		return NULL;
	}
	return term;
}

void terminal_free(terminal_t* term) {
	if (term == NULL)
		return;
	close(term->pipes.from_daemon[0]);
	close(term->pipes.from_daemon[1]);
	close(term->pipes.to_daemon[0]);
	close(term->pipes.to_daemon[1]);
	free(term);
}

int terminal_write_to_daemon(terminal_t* term, char* string) {
	if (term == NULL || string == NULL)
		return 0;
	return write(term->pins.terminal_write, string, strlen(string) + 1);
}

int terminal_write_to_terminal(terminal_t* term, char* string) {
	if (term == NULL || string == NULL)
		return 0;
	return write(term->pins.daemon_write, string, strlen(string) + 1);
}

char* terminal_read_from_daemon(terminal_t* term) {
	int res, i;
	char* ptr;

	if (term->pins._len_terminal == 0) {
		res = read(term->pins.terminal_read, &term->pins._buffer_terminal[term->pins._len_terminal], TERMINALS_BUFFER_SIZE - term->pins._len_terminal);
		if (res <= 0)
			return NULL;
		if (res > 0 && term->pins._buffer_terminal[res-1] != 0)
			term->pins._buffer_terminal[res++] = 0;
		term->pins._len_terminal += res;
		for (i = 0; i < term->pins._len_terminal; i++) {
			switch (term->pins._buffer_terminal[i]) {
			case '\n':
			case '\r':
				term->pins._buffer_terminal[i] = 0;
				break;
			}
		}
	}
	ptr = (char*) malloc(strlen(term->pins._buffer_terminal) + 1);
	strcpy (ptr, term->pins._buffer_terminal);
	// Sanitizing string
	res = strlen(ptr) + 1;
	for (i = res - 1; i>=0; i--) {
		switch (ptr[i]) {
		case '\r':
		case '\n':
		case ' ':
		case '\t':
		case 0:
			ptr[i] = 0;
			break;
		default:
			i = 0;
		}
	}
	do {
		memcpy (term->pins._buffer_terminal, &term->pins._buffer_terminal[res], term->pins._len_terminal - res);
		term->pins._len_terminal -= res;
		if (term->pins._buffer_terminal[0] == 0)
			res = 1;
	} while (term->pins._buffer_terminal[0] == 0 && res <= term->pins._len_terminal);
	return ptr;
}

char* terminal_read_from_terminal(terminal_t* term) {
	int res, i;
	char* ptr;

	if (term->pins._len_daemon == 0) {
		res = read(term->pins.daemon_read, &term->pins._buffer_daemon[term->pins._len_daemon], TERMINALS_BUFFER_SIZE - term->pins._len_daemon);
		if (res <= 0)
			return NULL;
		if (res > 0 && term->pins._buffer_daemon[res-1] != 0)
			term->pins._buffer_daemon[res++] = 0;
		term->pins._len_daemon += res;
		for (i = 0; i < term->pins._len_daemon; i++) {
			switch (term->pins._buffer_daemon[i]) {
			case '\n':
			case '\r':
				term->pins._buffer_daemon[i] = 0;
				break;
			}
		}
	}
	ptr = (char*) malloc(strlen(term->pins._buffer_daemon) + 1);
	strcpy (ptr, term->pins._buffer_daemon);
	// Sanitizing string
	res = strlen(ptr) + 1;
	for (i = res - 1; i>=0; i--) {
		switch (ptr[i]) {
		case '\r':
		case '\n':
		case ' ':
		case '\t':
		case 0:
			ptr[i] = 0;
			break;
		default:
			i = 0;
		}
	}
	do {
		memcpy (term->pins._buffer_daemon, &term->pins._buffer_daemon[res], term->pins._len_daemon - res);
		term->pins._len_daemon -= res;
		if (term->pins._buffer_daemon[0] == 0)
			res = 1;
	} while (term->pins._buffer_daemon[0] == 0 && res <= term->pins._len_daemon);
	return ptr;
}

int terminal_has_more_for_terminal(terminal_t* term) {
	int res;
	struct timeval timeout;
	fd_set fds;

	timeout.tv_sec = 0;
	timeout.tv_usec = 0;
	FD_ZERO(&fds);
	FD_SET(term->pins.terminal_read, &fds);

	if (select(term->pins.terminal_read + 1, &fds, NULL, NULL, &timeout) > 0)
		return 1;
	return term->pins._len_terminal;
}

int terminal_has_more_for_daemon(terminal_t* term) {
	int res;
	struct timeval timeout;
	fd_set fds;

	timeout.tv_sec = 0;
	timeout.tv_usec = 0;
	FD_ZERO(&fds);
	FD_SET(term->pins.daemon_read, &fds);

	if (select(term->pins.daemon_read + 1, &fds, NULL, NULL, &timeout) > 0)
		return 1;
	return term->pins._len_daemon;
}
